﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core;
using Cofe.Core.Filter;
using Cofe.Core.Implements;
using Cofe.Core.Interfaces;
using Cofe.Core.Property;
using Cofe.Core.Security;
using Cofe.Core.Utils;

namespace Cofe.Data
{
    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFEDB)]
    public class ParseAndUpdateDatabase : ParseOnly
    {
        #region Constructor

        public ParseAndUpdateDatabase()
        {
        }

        #endregion

        #region Methods

        public override async Task<IPropertyHost> TryParsePathAsync(string fullParsePath, ParsableType type,
            EntryConstructionFlags flags = EntryConstructionFlags.Default)
        {
            if (type == ParsableType.ParsePathLookup)
                flags |= EntryConstructionFlags.LookupIfParseFailed;

            if (type == ParsableType.AutoDetect)
                type = PathUtils.DetectParseType(fullParsePath);

            if (flags.HasFlag(EntryConstructionFlags.EnableCache))
            {
                FilterCollections fc = null;
                switch (type)
                {
                    case ParsableType.ParsePath:
                    case ParsableType.ParsePathLookup:
                        fc = FilterCollections.FromParseName(fullParsePath);
                        break;
                    case ParsableType.Guid:
                        var guid = new Guid(fullParsePath);
                        if (guid == CofeConstants.RootGuid)
                            return CofeServices.EntryConstructor.ConstructPropertyHost(PropertyProvider.ForUserRootDirectory());
                        fc = FilterCollections.FromGuid(guid);
                        break;
                }

                if (fc != null)
                    using (var repository = RepositoryFactory.CreateRepository())
                    {
                        var foundEntry = repository.FindAll(fc).FirstOrDefault();
                        if (foundEntry != null)
                        {
                            CofeServices.Logger.Log("PDPB: Parsed and Found Cached {0}", fullParsePath);
                            CofeServices.SecurityManager.DemandPermission<IPropertyHost>(foundEntry, PermissionType.List);
                            return foundEntry;
                        }
                    }
            }


            var nonCachedEntry = await base.TryParsePathAsync(fullParsePath, type, flags);

            //#if DEBUG //Non exists entry do not have PrimarPropertyProvider, have to regenerate when ConnectAsync()
            //            if (nonCachedEntry != null && nonCachedEntry.PrimaryPropertyProvider == null)
            //            {
            //                if (Debugger.IsAttached)
            //                    Debugger.Break();
            //                nonCachedEntry = await base.TryParsePathAsync(fullParsePath, type, flags);
            //                throw new Exception();
            //            }
            //#endif

            if (nonCachedEntry != null)
                using (var repository = CofeDBServices.RepositoryFactory.CreateRepository())
                {
                    string parseName = nonCachedEntry.Behaviors.GetProperty<string>(CofeProperties.FullParseName);
                    var dbEntry = repository.FindDbEntry(FilterCollections.FromParseName(parseName)).FirstOrDefault();
                    if (dbEntry != null)
                        nonCachedEntry.PropertyCache.PropertyCacheDictionary.CacheProperty
                            (PropertyPair.FromValue(CacheProperties.Id, dbEntry.Id));
                }

            if (nonCachedEntry != null && flags.HasFlag(EntryConstructionFlags.EnableCache))
            {
                var cofeAttribute = nonCachedEntry.Behaviors.GetProperty<CofeAttributes>(CofeProperties.CofeAttributes);


                if (!(cofeAttribute.HasFlag(CofeAttributes.NotCachable)))
                    if (CofeServices.CofeSettings.CacheUpdateOptions.HasFlag(CacheUpdateOptions.passiveUpdate))
                    {
                        CofeServices.Logger.Log("PDPB: Parsed and Adding to DB {0}", fullParsePath);
                        nonCachedEntry.Behaviors.InvokeAsync(DatabaseProperties.WriteRepositoryAsync,
                            new ParameterDic()
                            {
                                UpdateSubEntries = true,
                                Recursive = false
                            });
                    }
            }

            return nonCachedEntry;
        }


        #endregion

        #region Data

        IRepositoryFactory _repositoryFactory = null;

        #endregion

        #region Public Properties

        IRepositoryFactory RepositoryFactory
        {
            get { return _repositoryFactory ?? (_repositoryFactory = CofeServices.ServiceLocater.FindService<IRepositoryFactory>()); }
        }
        #endregion

    }
}
